use core::str;
use std::str::FromStr;

use serde::de::{self, IntoDeserializer};

use crate::{
    error::RedisError,
    resp::{
        CHAR_N, CHAR_R, TAG_ARRAY, TAG_BIG_NUMBER, TAG_BOOL, TAG_BULK_ERROR, TAG_BULK_STRING,
        TAG_DOUBLE, TAG_INTEGER, TAG_MAP, TAG_NIL, TAG_PUSHES, TAG_SET, TAG_SIMPLE_ERROR,
        TAG_SIMPLE_STRING, TAG_VERBATIM_STRING,
    },
    RedisResult,
};

pub struct Resp3Deserializer<'de> {
    buf: &'de [u8],
    pos: usize,
}

impl<'de> Resp3Deserializer<'de> {
    pub fn new(buf: &'de [u8]) -> Self {
        Resp3Deserializer { buf, pos: 0 }
    }

    pub fn peek(&mut self) -> RedisResult<&u8> {
        println!("peek {}", self.pos);
        if let Some(byte) = self.buf.get(self.pos) {
            self.advance(1);
            Ok(byte)
        } else {
            Err(self.eof())
        }
    }

    pub fn advance(&mut self, num: usize) {
        self.pos += num;
    }

    pub fn read_exact(&mut self, len: usize, is_check_end: bool) -> RedisResult<&[u8]> {
        let start = self.pos;
        let end = start + len;
        if self.buf.len() - 1 < end {
            return Err(RedisError::RespDeserialize(format!(
                "eof, expect end is {end}, buf len is {}",
                self.buf.len()
            )));
        }
        let data = &self.buf[start..end];
        self.advance(len);
        if is_check_end {
            match self.buf.get(self.pos) {
                Some(&CHAR_R) => {}
                Some(_) | None => {
                    return Err(RedisError::RespDeserialize(format!(
                        "the end of line \\r is not correct"
                    )));
                }
            }
            match self.buf.get(self.pos + 1) {
                Some(&CHAR_N) => {}
                Some(_) | None => {
                    return Err(RedisError::RespDeserialize(format!(
                        "the end of line \\n is not correct"
                    )));
                }
            }
            self.advance(2);
        }
        Ok(data)
    }

    pub fn read_line_end(&mut self) -> RedisResult<&[u8]> {
        let start = self.pos;
        loop {
            // let char1 = self.buf.get(cur1);
            // let char2 = self.buf.get(cur2);
            if let Some(c1) = self.buf.get(self.pos) {
                if c1 != &CHAR_R {
                    self.advance(1);
                    continue;
                }
            } else {
                return Err(self.eof());
            }
            if let Some(c2) = self.buf.get(self.pos + 1) {
                if c2 != &CHAR_N {
                    self.advance(1);
                    continue;
                }
            } else {
                return Err(self.eof());
            }
            let end = self.pos;
            if start >= end {
                return Err(self.eof());
            }
            self.advance(2);
            println!("readline, start = {}, end = {}", start, end);
            return Ok(&self.buf[start..end]);
        }
    }

    fn read_line_end_integer(&mut self) -> RedisResult<usize> {
        let res = String::from_utf8_lossy(self.read_line_end()?);
        match res.parse::<usize>() {
            Ok(val) => Ok(val),
            Err(err) => Err(RedisError::RespDeserialize(format!(
                "error on parse {res} to usize, {err}"
            ))),
        }
    }

    fn read_integer<T: FromStr + Copy>(&mut self) -> RedisResult<T> {
        let tag = self.peek()?;
        let result = match tag {
            &TAG_INTEGER => {
                let val = self.read_line_end()?; // length
                std::str::from_utf8(val)
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "unsupported type: {}",
                    tag
                )));
            }
        }
        .map_err(|err| RedisError::RespDeserialize(format!("{err}")))?;
        result
            .parse::<T>()
            .map_err(|_| RedisError::RespDeserialize("error on read as integer".to_string()))
    }

    fn read_val(&mut self, tag: u8) -> RedisResult<&str> {
        let first = self.peek()?;
        if first == &tag {
            let val = self.read_line_end()?; // length
            std::str::from_utf8(val).map_err(|err| RedisError::RespDeserialize(format!("{err}")))
        } else {
            return Err(RedisError::RespDeserialize(format!(
                "unsupported type: {}",
                first
            )));
        }
    }

    fn read_bulk_str_data(&mut self) -> RedisResult<&[u8]> {
        let len_bytes = self.read_line_end()?; // length
        let str = String::from_utf8(len_bytes.to_vec()).map_err(|err| {
            RedisError::new_resp_deserialize("the len format of bulk str is invalid", err)
        })?;
        let len = str.parse::<usize>().map_err(|err| {
            RedisError::new_resp_deserialize(
                format!("the len value = {str} of bulk str is invalid"),
                err,
            )
        })?;
        self.read_exact(len, true)
    }

    fn read_verbatim_str_data(&mut self) -> RedisResult<(&[u8], &[u8])> {
        let len_bytes = self.read_line_end()?; // length
        let str = String::from_utf8(len_bytes.to_vec()).map_err(|err| {
            RedisError::new_resp_deserialize("the len format of verbatim str is invalid", err)
        })?;
        let len = str.parse::<usize>().map_err(|err| {
            RedisError::new_resp_deserialize(
                format!("the len value = {str} of verbatim str is invalid"),
                err,
            )
        })?;
        let data = self.read_exact(len, true)?;
        let data_len = data.len();
        if data_len < 5 {
            return Err(RedisError::RespDeserialize(format!(
                "the format of verbatim string is invalid"
            )));
        }
        Ok((&data[0..3], &data[5..data_len]))
    }

    fn read_val_slice(&mut self) -> RedisResult<&[u8]> {
        let tag = self.peek()?;
        match tag {
            &TAG_BULK_STRING => self.read_bulk_str_data(),
            &TAG_SIMPLE_STRING => self.read_line_end(),
            &TAG_VERBATIM_STRING => {
                let (encoding, data) = self.read_verbatim_str_data()?;
                if encoding == b"txt" {
                    Ok(data)
                } else {
                    return Err(RedisError::RespDeserialize(format!(
                        "the encoding {encoding:?} of verbatim str is invalid"
                    )));
                }
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "the tag {tag} doesn't support"
                )));
            }
        }
    }

    fn eof(&self) -> RedisError {
        RedisError::RespDeserialize(format!("EOF at {}", self.pos))
    }
}

impl<'de, 'a> de::Deserializer<'de> for &'a mut Resp3Deserializer<'de> {
    type Error = RedisError;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        println!("deserialize_any");
        let first_byte = self.peek()?;
        match first_byte {
            &TAG_ARRAY => self.deserialize_seq(visitor),
            &TAG_BIG_NUMBER => self.deserialize_i128(visitor),
            &TAG_BOOL => self.deserialize_bool(visitor),
            &TAG_BULK_STRING => self.deserialize_bytes(visitor),
            &TAG_DOUBLE => self.deserialize_f64(visitor),
            &TAG_INTEGER => self.deserialize_i64(visitor),
            &TAG_MAP => self.deserialize_map(visitor),
            &TAG_NIL => self.deserialize_option(visitor),
            &TAG_SET => self.deserialize_seq(visitor),
            &TAG_SIMPLE_STRING => self.deserialize_str(visitor),
            &TAG_VERBATIM_STRING => self.deserialize_bytes(visitor),
            &TAG_PUSHES => todo!(),
            &TAG_SIMPLE_ERROR => todo!(),
            &TAG_BULK_ERROR => todo!(),
            _ => Err(RedisError::RespDeserialize(format!(
                "unsupported type: {}",
                first_byte
            ))),
        }
    }

    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let val = self.read_val(TAG_BOOL)?;
        visitor.visit_bool(match val {
            "t" => true,
            "f" => false,
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "could parse {val} to bool"
                )))
            }
        })
    }

    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i8(self.read_integer()?)
    }

    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i16(self.read_integer()?)
    }

    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i32(self.read_integer()?)
    }

    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_i64(self.read_integer()?)
    }

    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u8(self.read_integer()?)
    }

    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u16(self.read_integer()?)
    }

    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u32(self.read_integer()?)
    }

    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_u64(self.read_integer::<u64>()?)
    }

    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let val = self.read_val(TAG_DOUBLE)?;
        visitor.visit_f32(match val {
            "inf" | "+inf" => f32::INFINITY,
            "-inf" => f32::NEG_INFINITY,
            "nan" => f32::NAN,
            _ => val.parse::<f32>().map_err(|err| {
                RedisError::RespDeserialize(format!("error on parse {val} to f32, {err}"))
            })?,
        })
    }

    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let val = self.read_val(TAG_DOUBLE)?;
        visitor.visit_f64(match val {
            "inf" | "+inf" => f64::INFINITY,
            "-inf" => f64::NEG_INFINITY,
            "nan" => f64::NAN,
            _ => val.parse::<f64>().map_err(|err| {
                RedisError::RespDeserialize(format!("error on parse {val} to f64, {err}"))
            })?,
        })
    }

    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let val = self.read_val_slice()?;
        match std::str::from_utf8(val) {
            Ok(val) => {
                let len = val.chars().count();
                if len == 1 {
                    visitor.visit_char(val.chars().next().unwrap())
                } else {
                    Err(RedisError::RespDeserialize(format!(
                        "can't parse {val} to char, the str has {len} chars"
                    )))
                }
            }
            Err(err) => Err(RedisError::RespDeserialize(format!("{err}"))),
        }
    }

    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let val = self.read_val_slice()?;
        match str::from_utf8(val) {
            Ok(val) => visitor.visit_str(val),
            Err(err) => Err(RedisError::RespDeserialize(format!("{err}"))),
        }
    }

    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let tag = self.peek()?;
        let result = match tag {
            &TAG_BULK_STRING => self.read_bulk_str_data()?,
            &TAG_SIMPLE_STRING => self.read_line_end()?,
            &TAG_VERBATIM_STRING => {
                let (encoding, data) = self.read_verbatim_str_data()?;
                if encoding == b"txt" {
                    data
                } else {
                    return Err(RedisError::RespDeserialize(format!(
                        "the encoding {encoding:?} of verbatim str is invalid"
                    )));
                }
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "the tag {tag} doesn't support"
                )));
            }
        };
        match String::from_utf8_lossy(result) {
            std::borrow::Cow::Borrowed(str) => visitor.visit_string(str.to_owned()),
            std::borrow::Cow::Owned(str) => visitor.visit_string(str),
        }
    }

    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let tag = self.peek()?;
        let result = match tag {
            &TAG_BULK_STRING => self.read_bulk_str_data()?,
            &TAG_SIMPLE_STRING => self.read_line_end()?,
            &TAG_VERBATIM_STRING => {
                let (encoding, data) = self.read_verbatim_str_data()?;
                if encoding == b"txt" {
                    data
                } else {
                    return Err(RedisError::RespDeserialize(format!(
                        "the encoding {encoding:?} of verbatim str is invalid"
                    )));
                }
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "the tag {tag} doesn't support"
                )));
            }
        };
        visitor.visit_bytes(result)
    }

    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let tag = self.peek()?;
        let result = match tag {
            &TAG_BULK_STRING => self.read_bulk_str_data()?,
            &TAG_SIMPLE_STRING => self.read_line_end()?,
            &TAG_VERBATIM_STRING => {
                let (encoding, data) = self.read_verbatim_str_data()?;
                if encoding == b"txt" {
                    data
                } else {
                    return Err(RedisError::RespDeserialize(format!(
                        "the encoding {encoding:?} of verbatim str is invalid"
                    )));
                }
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "the tag {tag} doesn't support"
                )));
            }
        };
        visitor.visit_byte_buf(result.to_vec())
    }

    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.peek()? {
            &TAG_NIL => visitor.visit_none(),
            _ => visitor.visit_some(self),
        }
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        match self.peek()? {
            _ => visitor.visit_unit(),
        }
    }

    fn deserialize_unit_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_unit(visitor)
    }

    fn deserialize_newtype_struct<V>(
        self,
        _name: &'static str,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        println!("deserialize_seq");
        let tag = self.peek()?;
        match tag {
            &TAG_ARRAY => {
                let len = self.read_line_end_integer()?;
                println!("deserialize_seq len: {len}");
                visitor.visit_seq(SeqAccess { de: self, len })
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "the tag {tag} doesn't support"
                )));
            }
        }
    }

    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_tuple_struct<V>(
        self,
        _name: &'static str,
        _len: usize,
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        self.deserialize_seq(visitor)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let tag = self.peek()?;
        match tag {
            &TAG_MAP => {
                let len = self.read_line_end_integer()?;
                visitor.visit_map(MapAccess { de: self, len })
            }
            _ => Err(RedisError::RespDeserialize(format!(
                "the tag {tag} doesn't support"
            ))),
        }
    }

    fn deserialize_struct<V>(
        self,
        _name: &'static str,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        println!("deserialize_struct");
        let tag = self.peek()?;
        match tag {
            &TAG_MAP => {
                let len = self.read_line_end_integer()?;
                visitor.visit_map(MapAccess { de: self, len })
            }
            _ => Err(RedisError::RespDeserialize(format!(
                "the tag {tag} doesn't support"
            ))),
        }
    }

    fn deserialize_enum<V>(
        self,
        _name: &'static str,
        _variants: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        let tag = self.peek()?;
        let result = match tag {
            &TAG_BULK_STRING => self.read_bulk_str_data()?,
            &TAG_SIMPLE_STRING => self.read_line_end()?,
            &TAG_VERBATIM_STRING => {
                let (encoding, data) = self.read_verbatim_str_data()?;
                if encoding == b"txt" {
                    data
                } else {
                    return Err(RedisError::RespDeserialize(format!(
                        "the encoding {encoding:?} of verbatim str is invalid"
                    )));
                }
            }
            _ => {
                return Err(RedisError::RespDeserialize(format!(
                    "the tag {tag} doesn't support"
                )));
            }
        };
        match str::from_utf8(result) {
            Ok(val) => visitor.visit_enum(val.into_deserializer()),
            Err(err) => Err(RedisError::RespDeserialize(format!("{err}"))),
        }
    }

    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        println!(
            "deserialize_identifier, {}",
            std::any::type_name_of_val(&visitor)
        );
        self.deserialize_str(visitor)
    }

    fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
    where
        V: de::Visitor<'de>,
    {
        println!(
            "deserialize_ignored_any, {}",
            std::any::type_name_of_val(&visitor)
        );
        todo!()
    }
}

struct MapAccess<'a, 'de: 'a> {
    de: &'a mut Resp3Deserializer<'de>,
    len: usize,
}

impl<'de, 'a> serde::de::MapAccess<'de> for MapAccess<'a, 'de> {
    type Error = RedisError;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
    where
        K: de::DeserializeSeed<'de>,
    {
        println!("next key, len = {}", self.len);
        if self.len > 0 {
            self.len -= 1;
            seed.deserialize(&mut *self.de).map(Some)
        } else {
            Ok(None)
        }
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
    where
        V: de::DeserializeSeed<'de>,
    {
        println!("next value");
        seed.deserialize(&mut *self.de)
    }

    #[inline]
    fn size_hint(&self) -> Option<usize> {
        println!("map size hint");
        Some(self.len)
    }
}

struct SeqAccess<'a, 'de: 'a> {
    de: &'a mut Resp3Deserializer<'de>,
    len: usize,
}

impl<'de, 'a> serde::de::SeqAccess<'de> for SeqAccess<'a, 'de> {
    type Error = RedisError;

    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
    where
        T: de::DeserializeSeed<'de>,
    {
        println!("next element");
        if self.len > 0 {
            self.len -= 1;
            seed.deserialize(&mut *self.de).map(Some)
        } else {
            Ok(None)
        }
    }

    #[inline]
    fn size_hint(&self) -> Option<usize> {
        Some(self.len)
    }
}
